using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Sucrose.Base;

namespace Sucrose.Output
{
    public class SucroseOutputControl
    {
        private static SucroseOutputControl instance = null;

        public event ProgressUpdateHandler ProgressUpdates;

        private List<int> gradedIds;
        private bool importGrades;
        private bool importTasks;
        private bool downloadDocuments;
        private bool downloadSupport;

        /// <summary>
        /// Gets the instance of the SucroseOutputControl class
        /// </summary>
        /// <returns>The instance of the SucroseOutputControl class</returns>
        public static SucroseOutputControl GetInstance()
        {
            if (instance == null)
                instance = new SucroseOutputControl();
            return instance;
        }

        /// <summary>
        /// Sets the settings determining if support documents are downloaded to the user's hard drive
        /// </summary>
        public bool DownloadSupportDocuments
        {
            get
            {
                try
                {
                    int downloadSupportDocs = Settings.GetIntegerValueForKey("DownloadSupportDocuments");
                    return downloadSupportDocs == 1;
                }
                catch (KeyNotFoundException)
                {
                    DownloadSupportDocuments = true;
                    return true;
                }
            }
            set
            {
                if (value == true)
                    Settings.SetValueAtKey("DownloadSupportDocuments", 1);
                else
                    Settings.SetValueAtKey("DownloadSupportDocuments", 0);
            }
        }

        /// <summary>
        /// Sets the settings determining if task documents are downloaded to the user's hard drive
        /// and are attached to task items in outlook.
        /// </summary>
        public bool DownloadTaskDocuments
        {
            get
            {
                try
                {
                    int downloadTaskDocs = Settings.GetIntegerValueForKey("DownloadTaskDocuments");
                    return downloadTaskDocs == 1;
                }
                catch (KeyNotFoundException)
                {
                    DownloadTaskDocuments = true;
                    return true;
                }
            }
            set
            {
                if (value == true)
                    Settings.SetValueAtKey("DownloadTaskDocuments", 1);
                else
                    Settings.SetValueAtKey("DownloadTaskDocuments", 0);
            }
        }

        /// <summary>
        /// Sets the settings determining if grades are imported to the output
        /// </summary>
        public bool ImportGrades
        {
            get
            {
                try
                {
                    int importGrades = Settings.GetIntegerValueForKey("ImportGrades");
                    return importGrades == 1;
                }
                catch (KeyNotFoundException)
                {
                    ImportGrades = true;
                    return true;
                }
            }
            set
            {
                 if (value == true)
                    Settings.SetValueAtKey("ImportGrades", 1);
                else
                    Settings.SetValueAtKey("ImportGrades", 0);
            }
        }

        /// <summary>
        /// Sets the settings determining if tasks are imported to the output
        /// </summary>
        public bool ImportTasks
        {
            get
            {
                try
                {
                    int importTasks = Settings.GetIntegerValueForKey("ImportTasks");
                    return importTasks == 1;
                }
                catch (KeyNotFoundException)
                {
                    ImportTasks = true;
                    return true;
                }
            }
            set
            {
                 if (value == true)
                    Settings.SetValueAtKey("ImportTasks", 1);
                else
                    Settings.SetValueAtKey("ImportTasks", 0);
            }
        }

        /// <summary>
        /// Sets settings tracking which grades have been imported to outlook
        /// </summary>
        public List<int> GradedIds
        {
            get
            {
                List<int> gradedIds;
                try
                {
                    gradedIds = Settings.GetIntegerValuesForKey("ImportedGrades");
                }
                catch (KeyNotFoundException)
                {
                    gradedIds = new List<int>();
                    GradedIds = gradedIds;
                }

                return gradedIds;
            }
            set
            {
                Settings.SetValuesAtKey("ImportedGrades", value);
            }
        }

        /// <summary>
        /// Sets the last imported time for a course as the current time
        /// </summary>
        /// <param name="c">The course to set the last imported time</param>
        public void SetLastImported(Course c)
        {
            try
            {
                Settings.SetValueAtKey("LastImported[" + c.CourseNumber + "]", DateTime.Now.ToString());
            }
            catch (KeyNotFoundException)
            {
                Settings.SetValueAtKey("LastImported[" + c.CourseNumber + "]", DateTime.MinValue);
            }
        }

        /// <summary>
        /// Gets the time that a class was last imported from the settings file
        /// </summary>
        /// <param name="c">The course in question</param>
        /// <returns>The time the course was last imported</returns>
        public DateTime GetLastImported(Course c)
        {
            DateTime lastImported = DateTime.MinValue;
            try
            {
                lastImported = DateTime.Parse(Settings.GetValueForKey("LastImported[" + c.CourseNumber + "]"));
            }
            catch (KeyNotFoundException) { }
            catch (FormatException) { }

            return lastImported;
        }

        /// <summary>
        /// Starts off by getting the graded taskId's
        /// </summary>
        public SucroseOutputControl()
        {
            this.InitializeOutputSettings();

            ISucroseOutput outlook = new OutlookInterop();

            OutputInterop.AddGrade += outlook.AddGrade;
            OutputInterop.AddTask += outlook.AddTask;
            OutputInterop.TaskExists += outlook.TaskExists;
        }

        /// <summary>
        /// Gets all the settings from their properties and sets the instance variables
        /// </summary>
        public void InitializeOutputSettings()
        {
            this.gradedIds = GradedIds;
            this.importGrades = ImportGrades;
            this.importTasks = ImportTasks;
            this.downloadDocuments = DownloadTaskDocuments;
            this.downloadSupport = DownloadSupportDocuments;
        }

        /// <summary>
        /// Exports objects to Outlook.
        /// </summary>
        public void ExportCourses(List<Course> courses)
        {
            InitializeOutputSettings();

            foreach (Course c in courses)
            {
                ExportCourse(c);
            }
            ProgressUpdates(0, 0);
        }

        /// <summary>
        /// Outputs a single task
        /// </summary>
        /// <param name="course">The course this TaskItem belongs to</param>
        /// <param name="lastImported">The date this Task was last imported</param>
        public void ExportTask(TaskItem task, Course course, DateTime lastImported)
        {
            if (importTasks && OutputInterop.AddTask != null && OutputInterop.TaskExists != null)
            {
                if (task.DueDate != DateTime.MinValue && task.TaskIsCurrent() && !task.IsParent && !OutputInterop.TaskExists(task, lastImported))
                {
                    OutputInterop.AddTask(task, lastImported);
                }
                else
                {
                    if (task.DueDate == DateTime.MinValue)
                    {
                        Logger.Log("Not adding task '" + task.Name + "': No due date", MessageType.Info);
                    }
                }
            }

            if (importGrades && OutputInterop.AddGrade != null && lastImported != DateTime.MinValue)
            {
                if (!gradedIds.Contains(task.Id) && task.Grade != -1)
                {
                    OutputInterop.AddGrade(task);
                    gradedIds.Add(task.Id);
                    GradedIds = gradedIds;
                }
            }
        }

        /// <summary>
        /// Imports all tasks in the course
        /// </summary>
        public void ExportCourse(Course c)
        {
            DateTime lastImported = GetLastImported(c);
            int itemsToImport = 0;

            if(importTasks)
                itemsToImport = c.TaskItems.Count;

            LMSDownloader downloader = new LMSDownloader();
            downloader.ProgressUpdates += new ProgressUpdateHandler(ProgressUpdateRelay);
            downloader.ProgressOffset = itemsToImport;

            int itemsToDownload = 0;
            if (downloadSupport || downloadDocuments)
            {
                foreach (DownloadableItem item in c.DownloadableItems)
                {
                    SupportItem sItem = item as SupportItem;
                    TaskItem tItem = item as TaskItem;
                    
                    if ((sItem != null && downloadSupport) || (tItem != null && downloadDocuments))
                    {
                        itemsToDownload++;
                        downloader.AddDocument(item);
                    }
                }
            }

            downloader.DownloadDocuments();

            int currentItem = 0;
            foreach (TaskItem item in c.TaskItems)
            {
                ExportTask(item, c, lastImported);
                if (ProgressUpdates != null)
                    ProgressUpdates.Invoke(downloader.ItemsComplete + currentItem++, itemsToDownload + itemsToImport);
            }

            SetLastImported(c);
        }

        /// <summary>
        /// Forwards the update events to Control update events.
        /// </summary>
        /// <param name="currentTicks">Numerator of percent complete fraction</param>
        /// <param name="totalTicks">Denominator of percent complete fraction</param>
        private void ProgressUpdateRelay(int currentTicks, int totalTicks)
        {
            if (ProgressUpdates != null)
                ProgressUpdates.Invoke(currentTicks, totalTicks);
        }
    }
}
